package system_images

import (
	"gitee.com/theegg/go-brick/app/service/app"
	"gitee.com/theegg/go-brick/app/service/help/cfile"
	"gitee.com/theegg/go-brick/app/service/help/cimage"
	"github.com/gin-gonic/gin"
	"github.com/satori/go.uuid"
	"regexp"
	"strconv"
	"time"
)

var AllowedImageExt = [...]string{".jpeg", ".jpg", ".png", ".gif"}
var AllowedImageMaxSize = 2000

// if resize configure exist, then will resize the image
var ImageModuleResizeConfig = map[string]map[string]interface{}{
	"node_cover": {
		"width":   "156",
		"height":  "102",
		"quality": "80",
	},
}

// @title SaveImage
// @description save image to target dir
func SaveImage(module string, newDir string, c *gin.Context) (string, error) {
	header, errFile := c.FormFile("file")
	if errFile != nil {
		return "", errFile
	}

	fi, errOpen := header.Open()
	defer fi.Close()

	if errOpen != nil {
		return "", errOpen
	}

	// check file type
	fileType, errType := cimage.GetImageTypeFromFile(fi)
	if errType != nil {
		return "", errType
	}

	fileExt, errExt := GetFileExtFromType(fileType)
	if errExt != nil {
		return "", errExt
	}

	// prepare save
	uFt := uuid.NewV4()
	originFilename := header.Filename
	newFileName := uFt.String() + "." + fileExt

	image := new(SystemImages)
	image.Module = module
	image.Dir = newDir
	image.Ext = fileExt
	image.OriginName = originFilename
	image.Uuid = uFt.String()

	dir := module + app.PathSeparator + newDir + app.PathSeparator
	imageName := dir + newFileName

	image.ImageName = imageName

	// check resize
	resizeDir := ""
	if _, ok := ImageModuleResizeConfig[module+"_"+newDir]; ok {
		config := ImageModuleResizeConfig[module+"_"+newDir]
		resizeDir = module + app.PathSeparator + newDir + app.PathSeparator + config["width"].(string) + "x" + config["height"].(string) + app.PathSeparator

		image.Resize = 1
		image.Dir = resizeDir
		image.ImageName = resizeDir + newFileName
	}

	image.AddTime = time.Now().Unix()
	affected, errInsert := app.Db().Insert(image)
	if errInsert != nil {
		return "", app.NewError(errInsert)
	}

	if affected != 1 {
		return "", app.NewError("对不起, 新增图片失败")
	}

	// save the original image
	fullImageDir := app.GetImageUploadDir() + app.PathSeparator + dir

	errDir := cfile.CheckDirAndCreate(fullImageDir)
	if errDir != nil {
		return "", errDir
	}

	imageFullPath := fullImageDir + newFileName
	errSave := c.SaveUploadedFile(header, imageFullPath)
	if errSave != nil {
		return "", errSave
	}

	// save the resize image
	if image.Resize == 1 {
		fullResizeImageDir := app.GetImageUploadDir() + app.PathSeparator + resizeDir
		errDir := cfile.CheckDirAndCreate(fullResizeImageDir)
		if errDir != nil {
			return "", errDir
		}

		im, errIm := cimage.NewIm(imageFullPath)
		if errIm != nil {
			return "", errIm
		}

		config := ImageModuleResizeConfig[module+"_"+newDir]

		w, _ := strconv.Atoi(config["width"].(string))
		h, _ := strconv.Atoi(config["height"].(string))
		q, _ := strconv.Atoi(config["quality"].(string))
		im.Resize(w, h, q)

		rIm := im.ResizeIm()
		errSave := rIm.SaveImage(fullResizeImageDir + newFileName)
		if errSave != nil {
			return "", errSave
		}
	}

	return image.ImageName, nil
}

// 处理节点的图片状态
func ProcessItemImage(id int64, imageList map[string][]string) error {
	// 开启事务 插入数据
	session := app.Db().NewSession()
	defer session.Close()
	errSb := session.Begin()
	if errSb != nil {
		return app.NewError(errSb)
	}

	if len(imageList["add"]) > 0 {
		imageObj := new(SystemImages)
		imageObj.ItemId = id
		imageObj.State = 1
		affectedUpdate, errUpdate := session.In("image_name", imageList["add"]).Cols("item_id", "state").Update(imageObj)
		if errUpdate != nil {
			session.Rollback()
			return app.NewError(errUpdate)
		}

		if int(affectedUpdate) != len(imageList["add"]) {
			session.Rollback()
			return app.NewError("增加图片记录数不正确")
		}
	}

	if len(imageList["del"]) > 0 {
		imageObj := new(SystemImages)
		imageObj.State = 0
		affected, errDel := session.In("image_name", imageList["del"]).Cols("state").Update(imageObj)
		if errDel != nil {
			session.Rollback()
			return app.NewError(errDel)
		}

		if int(affected) != len(imageList["del"]) {
			session.Rollback()
			return app.NewError("删除图片记录数不正确")
		}
	}

	// 提交
	errCommit := session.Commit()
	if errCommit != nil {
		return app.NewError(errCommit)
	}

	return nil
}

// 图片格式是否符合内部图片结构
func ImageIsValidFormat(imageName string, prefixArgs ...string) bool {
	prefix := ""
	if len(prefixArgs) > 0 && prefixArgs[0] != "" {
		prefix = prefixArgs[0]
	} else {
		prefix = "[a-zA-zA-z\\/]{6, 36}"
	}

	pattern := "^" + prefix + "/[0-9a-zA-z\\-]{36}\\.(jpeg|JPEG|png|PNG|gif|GIF|jpg|JPG)$"
	res, err := regexp.MatchString(pattern, imageName)
	if err != nil {
		return false
	}

	if !res {
		return false
	}

	return true
}

// @title ImageIsExist
// @description 多图是否存在
func ImageIsExist(imageNameList []string) bool {
	itemList := make([]*SystemImages, 0)
	err := app.Db().In("image_name", imageNameList).Find(&itemList)
	if err != nil {
		return false
	}

	// 查找的图和提供的图长度不一样
	if len(itemList) != len(imageNameList) {
		return false
	}

	return true
}

// 获取图片的后缀
func GetFileExtFromType(imageType string) (string, error) {
	if imageType == cimage.GifType {
		return "gif", nil
	}

	if imageType == cimage.PngType {
		return "png", nil
	}

	if imageType == cimage.JpgType {
		return "jpeg", nil
	}

	return "", app.NewError("对不起, 不支持的图片类型")
}
